import hljs from "highlight.js";

// prettier-ignore
function createQueue() {
	const n = [];
	let t = !1,
		e = null;

	function u() {
		n.length > 0 ? ((t = !0), n.shift()()) : ((t = !1), e && e());
	}

	return {
		destroy: function() {
			n.splice(0, n.length);
		},
		enqueue: function(e) {
			return new Promise((c, i) => {
				n.push(async () => {
						try {
							await e(), c();
						} catch (n) {
							i(n);
						} finally {
							u();
						}
					}),
					t || u();
			});
		},
		finalcall: function(n) {
			e = n;
		},
	};
}

/**
 * @typedef {{
 *   beforeWord?(str:string,arrayIndex:number):void;
 *   afterWord?(str:string,arrayIndex:number):void;
 *   onPrinted?(content:string,char:string,charIndexInWord:number):void;
 *   finalcall?():void;
 *   withHLJS?:boolean;
 *   speed?:number;
 * }} Options
 */
/**
 * 打印字符打字机效果
 * @param {Options} options 配置项
 * @returns {{append: (str: string) => void;destroy: () => void;}}
 */
function printWords(options) {
	// prettier-ignore
	const {
		beforeWord,
		afterWord,
		onPrinted,
		finalcall,
		withHLJS = false,
		speed = 80
	} = options || {};

	const queue = createQueue();
	/**原始文本 */
	const words = [];
	/**打印完的文本 */
	let printed = "";
	/**打印的timer */
	let timer = null;

	let arrayIndex = -1;
	let charIndex = -1;

	function _print(str) {
		queue.enqueue(async () => {
			await new Promise((resolve) => {
				++arrayIndex;
				beforeWord && beforeWord(str, arrayIndex);
				const queue2 = createQueue();
				for (let i = 0; i < str.length; i++) {
					queue2.enqueue(async () => {
						await new Promise((resolve) => {
							charIndex = i;
							printed += str[i];
							onPrinted &&
								onPrinted(withHLJS ? _hl(printed) : printed,
									str[i], charIndex);
							clearTimeout(timer);
							timer = setTimeout(resolve, speed);
						});
					});
				}
				queue2.finalcall(() => {
					afterWord && afterWord(str, arrayIndex);
					resolve();
				});
			});
		});
	}

	/**
	 * 处理高亮
	 * @param {string} printed
	 */
	function _hl(printed) {
		const replacer = (s, $1, $2) => {
			if (!$2) return s;
			// prettier-ignore
			return `<pre><code class="hljs">${hljs.highlight($1, $2).value}</code></pre>`
		};
		return printed
			.replace(/```([\w\W]+?)\n([\w\W]+?)```/g, replacer)
			.replace(/```([\w\W]+?)\n([\w\W]+?)$/, replacer);
	}

	/**
	 * 追加文本
	 * @param {string} str 文本
	 */
	function append(str, isFinal = false) {
		if (isFinal) {
			queue.finalcall(() => {
				finalcall && finalcall();
				destroy();
			});
		}
		words.push(str);
		_print(str);
	}

	/**
	 * 停止并且销毁
	 */
	function stop() {
		queue.destroy();
		destroy();
	}

	/**销毁实例 */
	function destroy() {
		clearTimeout(timer);
	}

	return {
		append,
		stop,
		destroy,
	};
}

module.exports = printWords;